Actividades
Más reciente
False
Imagen de fondo del banner
Actividades UIAutomation
Última actualización 3 de abr. de 2024

Insertar código .NET

UiPath.Core.Activities.InjectDotNetCode

Descripción

Inyecta código .NET en el subproceso principal de interfaz de usuario de la aplicación de destino. Destinado al uso con aplicaciones .NET UI que no exponen tecnologías de automatización tradicionales o no pueden ser correctamente dirigidas por medios tradicionales.

Propiedades

Común
  • ContinuarEnCasoDeError: especifica si la automatización debe continuar incluso cuando la actividad arroja un error. Este campo solo admite valores Boolean (Verdadero, Falso). El valor predeterminado es Falso. Por lo tanto, si el campo está vacío y se produce un error, se detiene la ejecución del proyecto. Si el valor es Verdadero, la ejecución del proyecto continúa independientemente de cualquier error.

    Nota: si se incluye esta actividad en Intentar capturar y el valor de la propiedad ContinuarEnCasoDeError es Verdadero, no se detectará error cuando el proyecto se ejecute.
  • NombreParaMostrar: el nombre de la actividad para ser mostrado.
Entrada
  • Ensamblado: la ruta completa al ensamblado .NET compilado que quieres insertar. Este campo solo admite cadenas y variables String.
  • Nombre del método: el nombre del método que quieres ejecutar. Solo se admiten métodos estáticos públicos.

    Nota: Un tipo no puede contener varios métodos con el mismo nombre. En este caso, se produce un error en el tiempo de ejecución.
  • Destino.Región de recorte: define el rectángulo de recorte, en píxeles, en relación con el Elemento de IU, en las siguientes direcciones: izquierda, arriba, derecha y abajo. Admite números positivos y negativos.
  • ElementoDeDestino : usa la variable ElementoDeIU devuelta por otra actividad. Esta propiedad no se puede utilizar junto con la propiedad Selector. Este campo solo admite variables de Elemento de IU.
  • Target.Selector : propiedad de texto utilizada para encontrar un elemento de IU concreto cuando se ejecuta la actividad. En realidad, es un fragmento XML que especifica atributos del elemento GUI que está buscando y de algunos de sus elementos principales.
  • Target.TimeoutMS : especifica la cantidad de tiempo (en milisegundos) que se debe esperar a que se ejecute la actividad antes de que se produzca el error SelectorNotFoundException . El valor predeterminado es 30 000 milisegundos (30 segundos).
  • Destino.EsperaListo : antes de realizar las acciones, espera a que el destino esté listo. Están disponibles las siguientes opciones:

    • Ninguno: no espera a que exista nada, excepto el elemento de interfaz de usuario de destino, antes de ejecutar la acción. Por ejemplo, puedes utilizar esta opción si quieres recuperar solo el texto de una página web o hacer clic en un botón concreto, sin tener que esperar a que se carguen todos los elementos de la interfaz de usuario. Ten en cuenta que esto puede tener consecuencias no deseadas si el botón depende de elementos que aún no están cargados, como los scripts.
    • Interactivo / Completo : espera que existan todos los elementos de IU de la aplicación de destino antes de ejecutar la acción.

      Para evaluar si una aplicación está en estado Interactivo o Completo, se verifican las siguientes etiquetas:

    • Aplicaciones de escritorio: se envía un mensaje wm_null para comprobar la existencia de las etiquetas <wnd>, <ctrl>, <java> o <uia>.Si existen, se ejecuta la actividad.
    • Aplicaciones web:
    1. Internet Explorer: la etiqueta <webctrl> se utiliza para comprobar si el estado Listo del documento HTML es Completo. Además, el Ocupado tiene que estar en "Falso".
    2. Otros: la etiqueta <webctrl> se utiliza para comprobar si el estado Listo del documento HTML está Completo.
    • Aplicaciones SAP: primero se verifica la presencia de la etiqueta <wnd>, después se utiliza una API específica de SAP para detectar si la sesión está ocupada o no.
  • TipoDeNombre: el nombre de la clase pública que contiene el método en ejecución. Este campo solo admite cadenas y variables String.
Otros
  • Privado : si se selecciona, los valores de variables y argumentos ya no se registran en el nivel Detallado.
Salida
  • Resultado: el resultado del método invocado, almacenado en una variable Object. Este campo solo admite variables Object.

Inyectar código en dominios de aplicación no predeterminados

La actividad Inyectar código .NET inyecta código solo en el DominioDeAplicación predeterminado.

Algunas aplicaciones están estructuradas de forma que los elementos a los que puedes necesitar acceder o manipular no se encuentran dentro del DominioDeAplicación predeterminado, por lo que no basta con introducir código en el DominioDeAplicación predeterminado. Por lo tanto, si los elementos de la IU que quieres indicar están ubicados en otro DominioDeAplicación, no estarán disponibles para el código inyectado.

Para solucionarlo, debes modificar el proceso de inyección para apuntar al DominioDeAplicación preciso que contiene los elementos de la IU. Más exactamente, debes inyectar el código de la función que se ejecuta en el DominioDeAplicación predeterminado en todos los DominiosDeAplicación no predeterminados o en el DominioDeAplicación no predeterminado específico que contiene los elementos de la IU que deseas indicar.

Crear un ejecutor Cross AppDomain

Para ejecutar código en dominios de aplicación no predeterminados, debes crear una clase derivada de MarshalByRefObject que contenga la función que quieres ejecutar en dominios de aplicación no predeterminados:
public class CrossAppDomainRunner : MarshalByRefObject
{
    public void Execute(IntPtr controlHandle)
    {
        // Implementation of the method that will be executed in the target AppDomain
        Trace.WriteLine("Sunt in " + AppDomain.CurrentDomain.FriendlyName);

        Control foundControl = null;
        try
        {
            foundControl = Control.FromHandle(controlHandle);
        }
        catch (Exception controlException)
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ An exception occurred while getting the control from handle {controlHandle}. The message is: {controlException.Message}, Win32 Error: {lastWin32Error}");
            
        }
        if (foundControl != null)
        {
            Trace.WriteLine($"+++++ Found control {foundControl.Name} from handle {controlHandle}");
            
        }
        else
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ Control NOT found based on handle {controlHandle}, Win32 Error: {lastWin32Error}");
            
        }
    }
}public class CrossAppDomainRunner : MarshalByRefObject
{
    public void Execute(IntPtr controlHandle)
    {
        // Implementation of the method that will be executed in the target AppDomain
        Trace.WriteLine("Sunt in " + AppDomain.CurrentDomain.FriendlyName);

        Control foundControl = null;
        try
        {
            foundControl = Control.FromHandle(controlHandle);
        }
        catch (Exception controlException)
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ An exception occurred while getting the control from handle {controlHandle}. The message is: {controlException.Message}, Win32 Error: {lastWin32Error}");
            
        }
        if (foundControl != null)
        {
            Trace.WriteLine($"+++++ Found control {foundControl.Name} from handle {controlHandle}");
            
        }
        else
        {
            int lastWin32Error = Marshal.GetLastWin32Error();
            Trace.WriteLine($"+++++ Control NOT found based on handle {controlHandle}, Win32 Error: {lastWin32Error}");
            
        }
    }
}
Básicamente, tienes una función Execute que recibe un parámetro IntPtr . Este parámetro contiene el valor del control que está intentando encontrar. En este ejemplo, solo necesitas pasar un parámetro IntPtr , pero en tu situación particular, puedes añadir tantos parámetros como quieras.

Enumerar e inyectar código en dominios de aplicación no predeterminados

Para enumerar los otros AppDomains, necesitas un puntero a la interfaz ICorRuntimeHost desde mscoree. Para ello, debes declarar esa interfaz:
using System;
                using System.Collections.Generic;
                using System.Diagnostics;
                using System.Reflection;
                using System.Runtime.InteropServices;
                
                namespace mscoree
                {
                [CompilerGenerated]
                [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
                [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
                [TypeIdentifier]
                [ComImport]
                [CLSCompliant(false)]
                public interface ICorRuntimeHost
                {
                void _VtblGap1_11();
                
                void EnumDomains(out IntPtr enumHandle);
                
                void NextDomain([In] IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)] out object appDomain);
                
                void CloseEnum([In] IntPtr enumHandle);
                }
                }using System;
                using System.Collections.Generic;
                using System.Diagnostics;
                using System.Reflection;
                using System.Runtime.InteropServices;
                
                namespace mscoree
                {
                [CompilerGenerated]
                [Guid("CB2F6722-AB3A-11D2-9C40-00C04FA30A3E")]
                [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
                [TypeIdentifier]
                [ComImport]
                [CLSCompliant(false)]
                public interface ICorRuntimeHost
                {
                void _VtblGap1_11();
                
                void EnumDomains(out IntPtr enumHandle);
                
                void NextDomain([In] IntPtr enumHandle, [MarshalAs(UnmanagedType.IUnknown)] out object appDomain);
                
                void CloseEnum([In] IntPtr enumHandle);
                }
                } 

Debes declarar una clase que contenga métodos nativos para inicializar el Modelo de objetos componentes (COM):

public static class NativeMethods
                {
                
                [DllImport("ole32.dll")]
                public static extern int CoInitializeEx(IntPtr pvReserved, COINIT dwCoInit);
                
                public enum COINIT : uint
                {
                /// Initializes the thread for multi-threaded object concurrency.
                COINIT_MULTITHREADED = 0x0,
                /// Initializes the thread for apartment-threaded object concurrency. 
                COINIT_APARTMENTTHREADED = 0x2,
                // ...
                }
                }public static class NativeMethods
                {
                
                [DllImport("ole32.dll")]
                public static extern int CoInitializeEx(IntPtr pvReserved, COINIT dwCoInit);
                
                public enum COINIT : uint
                {
                /// Initializes the thread for multi-threaded object concurrency.
                COINIT_MULTITHREADED = 0x0,
                /// Initializes the thread for apartment-threaded object concurrency. 
                COINIT_APARTMENTTHREADED = 0x2,
                // ...
                }
                }   
Necesitas un método para obtener un objeto ICorRunttimeHost :
public static ICorRuntimeHost GetCorRuntimeHost()
                {
                return (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }public static ICorRuntimeHost GetCorRuntimeHost()
                {
                return (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }
Ahora tienes todo listo para enumerar los otros AppDomains y ejecutar código en ellos. La función GetControlData es ejecutada por la actividad Inyectar código .NET en el DominioDeAplicación predeterminado:
public static void GetControlData(Int64 controlHandle, out string response)
                {
                //initialising COM
                NativeMethods.CoInitializeEx(IntPtr.Zero, NativeMethods.COINIT.COINIT_MULTITHREADED);
                
                mscoree.ICorRuntimeHost host = null;
                try
                {
                host = (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }
                catch (COMException comEx)
                {
                Trace.WriteLine($"COMException: {comEx.Message}, HRESULT: {comEx.ErrorCode}");
                }
                catch (Exception ex)
                {
                // Handle other exceptions
                Trace.WriteLine($"Exception: {ex.Message}");
                }
                
                
                
                IntPtr enumHandle = IntPtr.Zero;
                
                try
                {
                //now that we have ICorRuntimeHost object we can use it to enumerate the other domains
                host.EnumDomains(out enumHandle);
                object domain = null;
                host.NextDomain(enumHandle, out domain);
                while (domain != null)
                {
                //for each appdomain obtained
                AppDomain appDomain = (AppDomain)domain;
                //appDomain.BaseDirectory; - you might want to copy your dll 
                //in the appDomain.BaseDirectory cause otherwise it might not find 
                //the assembly 
                
                ObjectHandle handle = appDomain.CreateInstance(
                typeof(CrossAppDomainRunner).Assembly.FullName,
                typeof(CrossAppDomainRunner).FullName);
                
                // Unwrap to get the actual object
                
                var runnerProxy = handle.Unwrap();
                
                // Use reflection to call the Execute method
                MethodInfo executeMethod = runnerProxy.GetType().GetMethod("Execute", new Type[] { typeof(IntPtr) });
                //pass parameters as new object[]
                executeMethod.Invoke(runnerProxy, new object[] { new IntPtr(controlHandle) });
                
                //go to next appdomain
                host.NextDomain(enumHandle, out domain);
                if (domain == null)
                break;
                
                }
                }
                finally
                {
                if (host != null)
                {
                if (enumHandle != IntPtr.Zero)
                {
                host.CloseEnum(enumHandle);
                }
                
                Marshal.ReleaseComObject(host);
                }
                
                }
                response = string.Empty;
                }public static void GetControlData(Int64 controlHandle, out string response)
                {
                //initialising COM
                NativeMethods.CoInitializeEx(IntPtr.Zero, NativeMethods.COINIT.COINIT_MULTITHREADED);
                
                mscoree.ICorRuntimeHost host = null;
                try
                {
                host = (ICorRuntimeHost)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("CB2F6723-AB3A-11D2-9C40-00C04FA30A3E")));
                }
                catch (COMException comEx)
                {
                Trace.WriteLine($"COMException: {comEx.Message}, HRESULT: {comEx.ErrorCode}");
                }
                catch (Exception ex)
                {
                // Handle other exceptions
                Trace.WriteLine($"Exception: {ex.Message}");
                }
                
                
                
                IntPtr enumHandle = IntPtr.Zero;
                
                try
                {
                //now that we have ICorRuntimeHost object we can use it to enumerate the other domains
                host.EnumDomains(out enumHandle);
                object domain = null;
                host.NextDomain(enumHandle, out domain);
                while (domain != null)
                {
                //for each appdomain obtained
                AppDomain appDomain = (AppDomain)domain;
                //appDomain.BaseDirectory; - you might want to copy your dll 
                //in the appDomain.BaseDirectory cause otherwise it might not find 
                //the assembly 
                
                ObjectHandle handle = appDomain.CreateInstance(
                typeof(CrossAppDomainRunner).Assembly.FullName,
                typeof(CrossAppDomainRunner).FullName);
                
                // Unwrap to get the actual object
                
                var runnerProxy = handle.Unwrap();
                
                // Use reflection to call the Execute method
                MethodInfo executeMethod = runnerProxy.GetType().GetMethod("Execute", new Type[] { typeof(IntPtr) });
                //pass parameters as new object[]
                executeMethod.Invoke(runnerProxy, new object[] { new IntPtr(controlHandle) });
                
                //go to next appdomain
                host.NextDomain(enumHandle, out domain);
                if (domain == null)
                break;
                
                }
                }
                finally
                {
                if (host != null)
                {
                if (enumHandle != IntPtr.Zero)
                {
                host.CloseEnum(enumHandle);
                }
                
                Marshal.ReleaseComObject(host);
                }
                
                }
                response = string.Empty;
                }

El ejemplo anterior inyecta el código en todos los AppDomains. Una vez que encuentres el DominioDeAplicación donde se encuentran los elementos de la IU que quieres indicar, puedes enumerar todos los DominiosDeAplicación, pero inyectar código solo en el DominioDeAplicación necesario.

Was this page helpful?

Obtén la ayuda que necesitas
RPA para el aprendizaje - Cursos de automatización
Foro de la comunidad UiPath
Logotipo blanco de UiPath
Confianza y seguridad
© 2005-2024 UiPath. All rights reserved.